package com.googlecode.chigscommons.web.common.modal;

import com.googlecode.chigscommons.repository.UncheckedRuntimeException;

import org.apache.wicket.Page;
import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.WebComponent;
import org.apache.wicket.markup.html.form.upload.FileUpload;
import org.apache.wicket.markup.html.link.IPageLink;
import org.apache.wicket.markup.html.link.InlineFrame;
import org.apache.wicket.markup.html.panel.Panel;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;


public abstract class UploadPanel<T extends Serializable> extends Panel {
    private InlineFrame uploadIFrame = null;

	private static final Map<String, Serializable> resultMap = new HashMap<String, Serializable>();
	
	public UploadPanel(String id) {
		super(id);
		addOnUploadedCallback();
		setOutputMarkupId(true);
	}

	/**
	 * Called when the upload load is uploaded and ready to be used Return the
	 * url of the new uploaded resource
	 */
	public abstract String onFileUploaded(FileUpload upload);

	/**
	 * Called once the upload is finished and the traitment of the
	 * {@link FileUpload} has been done in {@link UploadPanel#onFileUploaded}
	 * 
	 */
	public abstract void onUploadFinished(AjaxRequestTarget target, T result);

	@Override
	protected void onBeforeRender() {
		super.onBeforeRender();
		if (uploadIFrame == null) {
			// the iframe should be attached to a page to be able to get its
			// pagemap,
			// that's why i'm adding it in onBeforRender
			addUploadIFrame();
		}
	}

	/**
	 * Create the iframe containing the upload widget
	 * 
	 */
	private void addUploadIFrame() {
		IPageLink iFrameLink = new IPageLink() {
			@Override
			public Page getPage() {
				return new UploadIFrame() {
					@Override
					protected String getOnUploadedCallback() {
						return "onUpload_" + UploadPanel.this.getMarkupId();
					}

					@Override
					protected String manageInputSream(FileUpload upload) {
						return UploadPanel.this.onFileUploaded(upload);
					}
				};
			}

			@Override
			public Class<UploadIFrame> getPageIdentity() {
				return UploadIFrame.class;
			}
		};
		uploadIFrame = new InlineFrame("upload", getPage().getPageMap(), iFrameLink);
		add(uploadIFrame);
	}

	/**
	 * Hackie method allowing to add a javascript in the page defining the
	 * callback called by the innerIframe
	 * 
	 */
	private void addOnUploadedCallback() {
		final OnUploadedBehavior onUploadBehavior = new OnUploadedBehavior();
		add(onUploadBehavior);
		add(new WebComponent("onUploaded") {
			@Override
			protected void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) {
				// calling it through setTimeout we ensure that the callback is
				// called
				// in the proper execution context, that is the parent frame
				replaceComponentTagBody(
						markupStream,
						openTag,
						"function onUpload_"
						+ UploadPanel.this.getMarkupId()
						+ "(clientFileName, newFileUrl) {window.setTimeout(function() { "
						+ onUploadBehavior.getCallback() + " }, 0 )}");
			}
		});
	}

	private class OnUploadedBehavior extends AbstractDefaultAjaxBehavior {
		public String getCallback() {
			return generateCallbackScript(
					"wicketAjaxGet('"
					+ getCallbackUrl(false)
					+ "&newFileUrl=' + encodeURIComponent(newFileUrl)"
					+ " + '&clientFileName=' + encodeURIComponent(clientFileName)")
					.toString();
		}

		@Override
		protected void respond(AjaxRequestTarget target) {
			UploadPanel.this.onUploadFinished(target, removeUploadResult(getRequest().getParameter("clientFileName")));
		}
	}

	@SuppressWarnings("unchecked")
	public T removeUploadResult(String key) {
		if (!resultMap.containsKey(key)) {
			throw new UncheckedRuntimeException("No upload result for key="+key);
		}
		T r =  (T) resultMap.get(key);
		resultMap.remove(key);
		return r;
	}

	public void putUploadResult(String key, T uploadResult) {
		resultMap.put(key, uploadResult);
	}
		
}
